﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WaterForecast.manager;
using WaterForecast.entity;
using System.Windows.Threading;


namespace WaterForecast
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        ReportDataManager rdMan;
        DispatcherTimer timer;  //计时器，用于进度条控制
        double stepSize = 5;    //进度条每次增加的值
        int currentStationSequence = 1; //当前在计算中的站点的序号，用于计算进度条

        String[] stationNames = { "朱沱站", "石鼓站", "桐子林站", "高场站", "瀑布沟", "紫坪铺", "平武站", "小河坝站", "罗渡溪站", "乌江渡站", "武隆站", "富顺站", "广元站", "武胜站", "北碚站"};  //站点名称数组
        Dictionary<String, List<StationFlowData>> forcastResultData; //所有站点的预测结果

        Thread forcastThread = null;    //预测线程

        public MainWindow()
        {
            InitializeComponent();
            rdMan = new ReportDataManager();
            forcastResultData = new Dictionary<String, List<StationFlowData>>();
            //forcastThread = new Thread(new ThreadStart(forcastThreadFunction));
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            while (Directory.Exists(XmlConfigManager.Man.GetRHFSPath() + XmlConfigManager.Man.GetFlowDataPath()) == false)
            {
                RHFSFilePathSetClicked(null, null);
            }
            //PlaceManager.Man.PredictTime = rdpPredictTime.SelectedDate.Value;
            //查找方法名称
            String planNameFilePath = XmlConfigManager.Man.GetRHFSPath() + "/plans/planname.txt";
            if (!File.Exists(planNameFilePath))
            {
                MessageBox.Show("请先配置方法名称！");
            }
            StreamReader sr = new StreamReader(planNameFilePath, Encoding.Default);
            String planName = sr.ReadLine();    //读取方法名称
            sr.Close();

            //查找预报开始时间
            String planParameterFilePath = XmlConfigManager.Man.GetRHFSPath() + "/plans/" + planName + "/方法设置.txt";
            sr = new StreamReader(planParameterFilePath, Encoding.Default);
            int predictTimeLineNumber = 3;  //预报开始时间所在行号
            String predictTimeString = "";
            while (predictTimeLineNumber-- > 0) //循环到预报开始时间所在行，进行读取
            {
                predictTimeString = sr.ReadLine();    //预报开始时间
            }
            //将预报开始时间字符串转换成DateTime类型
            predictTimeString = predictTimeString.Split(new char[] { ':', '：' }, StringSplitOptions.RemoveEmptyEntries)[1].Trim();
            String[] predictTimeArray = predictTimeString.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
            int predictTimeYear = Convert.ToInt32(predictTimeArray[0]); //年
            int predictTimeMonth = Convert.ToInt32(predictTimeArray[1]);//月
            int predictTimeDay = Convert.ToInt32(predictTimeArray[2]);  //日
            int predictTimeHour = Convert.ToInt32(predictTimeArray[3]); //时
            //构造DateTime类型的预报开始时间
            PlaceManager.Man.PredictTime = new DateTime(predictTimeYear, predictTimeMonth, predictTimeDay, predictTimeHour, 0, 0);

            //设置进度条timer相关参数
            this.timer = new DispatcherTimer();
            this.timer.Interval = TimeSpan.FromMilliseconds(1);
            this.timer.Tick += new EventHandler(this.Timer_Tick);
        }

        private void RHFSFilePathSetClicked(object sender, RoutedEventArgs e)
        {
            //有修改
            System.Windows.Forms.FolderBrowserDialog open = new System.Windows.Forms.FolderBrowserDialog();
            open.ShowDialog();
            String path = open.SelectedPath;
            //String patha = System.Windows.Forms.Application.StartupPath;
            //path = path.Substring(0, path.Length - 4);
            //label5.Text = path + "hahha";
            if (path != "")
            {
                if (Directory.Exists(path + "\\下载数据") == true)
                {
                    SetConfigXMLValue(path, "/root/RHFSFilePath");

                    if (Directory.Exists(XmlConfigManager.Man.GetExerciseDataPath()) == false)//如果不存在就创建file文件夹
                    {
                        Directory.CreateDirectory(XmlConfigManager.Man.GetExerciseDataPath());
                    }
                    if (Directory.Exists(XmlConfigManager.Man.GetSaveDataPath()) == false)//如果不存在就创建file文件夹
                    {
                        Directory.CreateDirectory(XmlConfigManager.Man.GetSaveDataPath());
                    }
                }
            }
        }

        void SetConfigXMLValue(String value, String xmlpath)
        {

            XmlDocument xml = new XmlDocument();
            xml.Load(Environment.CurrentDirectory + "//Config.xml");
            XmlNodeList nodelist = xml.SelectNodes(xmlpath);
            nodelist[0].InnerText = value;
            xml.Save(Environment.CurrentDirectory + "//Config.xml");
        }

        //进度条timer触发事件
        private void Timer_Tick(object sender, EventArgs e)
        {
            calculateProgressBar.Value += this.stepSize;
            int value = Math.Max(0, Math.Min(100, Convert.ToInt32((calculateProgressBar.Value / (calculateProgressBar.Maximum - calculateProgressBar.Minimum)) * 100)));
            
            calculateProgressLable.Content = "计算进度： " + value.ToString() + " %";
            int stationCount = stationNames.Length;
            if (value >= (currentStationSequence / stationCount) * 100) this.timer.Stop();
        }

        private void Timer_Restart()
        {
            this.timer.Stop();
            calculateProgressBar.Value = calculateProgressBar.Minimum;
            //this.timer.Start();
        }

        //训练网络
        private void trainNetwork()
        {
            //检查是否设置了预测站点
            if (null == PlaceManager.Man.PlaceName || PlaceManager.Man.PlaceName.Equals(""))
            {
                MessageBox.Show("请选择预测站点！");
                return;
            }

            //this.stepSize = 15;  //设置进度条每次增加的值
            //Timer_Restart();    //重新开始进度条

            //logTileViewItem.Content = "";
            DateTime zhidingshijian = PlaceManager.Man.PredictTime; //目前暂时指定为2011-09-01
            //从程序界面读取控制参数并存储
            Int32 jds = 10;//定义网络节点数
            Double xxl = 1.3;//定义网络学习率
            Double jdkz = 0.0001;//定义精度控制
            Int32 xhcs = 10000;//定义最大循环次数
            int yuceshijian = 0;
            //logTileViewItem.Content += ("参数情况如下：" + "\n" + "隐层结点数：" + jds + "\n" + "学习率：" + xxl + "\n" + "精度要求误差小于：" + jdkz + "\n" + "最大循环次数" + xhcs + "\n");
            // MessageBox.Show("网络训练参数已确定！");

            //对权矩阵随机赋值
            Int32 OUT_COUT = 40;    //输出向量维数，每天8个，一共5天
            Int32 IN_COUT = 160;     //输入向量维数，2个站点，每个10天

            Int32 h = jds;
            int i, j;
            double[,] v = new Double[IN_COUT, jds];   //隐藏层权矩阵,允许隐层节点最大数量为100
            double[,] w = new Double[jds, OUT_COUT];   //输出层权矩阵
            //srand((unsigned)time(NULL));
            Random rnd = new Random();//随机对象

            // label5.Text = ("随机赋值情况如下：" + "\n");
            //为隐藏层及输出层权矩阵随机赋值
            for (i = 0; i < IN_COUT; i++)
            {
                for (j = 0; j < h; j++)
                {
                    v[i, j] = rnd.Next(0, 100);//随机赋值0~100
                    v[i, j] = v[i, j] / 100;//转换为0~1之间的两位小数
                    //label5.Text += ("v[" + i + "," + j + "]=" + v[i, j] + "\t");//在主界面上显示
                };
                //label5.Text += ("\n");
            }
            for (i = 0; i < h; i++)
            {
                for (j = 0; j < OUT_COUT; j++)
                {
                    w[i, j] = rnd.Next(0, 100);//随机赋值0~100
                    w[i, j] = w[i, j] / 100;//转换为0~1之间的两位小数
                    //label5.Text += ("w[" + i + "," + j + "]=" + w[i, j] + "\t");//在主界面上显示
                };
                // label5.Text += ("\n");
            }

            // MessageBox.Show("权矩阵已随机赋值！");

            //Int32 OUT_COUT = 2;    //输出向量维数
            //Int32 IN_COUT = 3;     //输入向量维数，站点数
            Int32 COUT = 1;    //样本数量，一日8个,此处暂时用例子中的6个
            //Int32 biaoji = 0;
            //Int32 h = 10;
            double a = xxl;
            double b = jdkz;
            Int32 LoopCout = xhcs;



            Int32 len;    //流量数据行数
            //int i, j;
            int lenX = 0;//每行数据个数

            Double[,] shuzu = new double[100000, 100];
            string[,] strArrX = new string[100000, 100];
            string[] strArr = new string[100000];
            string[] strout = new string[100000];
            bool fe = File.Exists(PlaceManager.Man.FilePath);

            if (fe == false)
            {
                MessageBox.Show("原始流量文件不存在！");

            }
            else
            {
                // File.Open(PlaceManager.Man.FilePath, FileMode.Open);
                strArr = File.ReadAllLines(PlaceManager.Man.FilePath, Encoding.Default);//以文本方式逐行读取
            }

            //ReadAllLines("F:\\金沙江干支流：流量数据.txt", Encoding.Default);//以文本方式逐行读取

            len = strArr.GetLength(0);//计算文件行数
            //logTileViewItem.Content += "文件数据行数" + len + "\n";//显示文件行数

            for (j = len - 1; j > 0; j--)
            {
                i = 0;
                for (int ctr = 0; ctr < strArr[j].Length - 1; ctr++)//对每行数据以字符为单位，逐个扫描
                {
                    if (strArr[j][ctr] == (' ') & strArr[j][ctr + 1] != (' '))//以一个或多个空格为分隔，按字符串方式存储到数组
                        i = i + 1;
                    else
                        strArrX[j, i] += strArr[j][ctr];
                }
                DateTime Time = DateTime.Parse(strArrX[j, 0] + " " + strArrX[j, 1]);
                if (Time < zhidingshijian)
                {
                    yuceshijian = j;

                    break;
                }
            }
            //以下部分采用逐字符方式读取，是否很浪费时间，有没有什么高效的办法实现数据读取 ？？
            //从文件末尾读取所需数据，本次读最后12天

            for (j = yuceshijian - 208; j < yuceshijian - 8; j++)
            {
                StationFlowData flowdata = new StationFlowData();

                i = 0;
                for (int ctr = 0; ctr < strArr[j].Length - 1; ctr++)//对每行数据以字符为单位，逐个扫描
                {
                    if (strArr[j][ctr] == (' ') & strArr[j][ctr + 1] != (' '))//以一个或多个空格为分隔，按字符串方式存储到数组
                        i = i + 1;
                    else
                        strArrX[j, i] += strArr[j][ctr];
                }
                lenX = i;//统计每行含有的数据个数
                //label5.Text += ("\n数组含" + (lenX + 1) + "个数");
                for (i = 2; i <= lenX; i++)//排除日期和时间，从第三列开始全部转换为双精度格式
                {
                    shuzu[j, i] = Convert.ToDouble(strArrX[j, i]);
                }

            }



            //对网络进行训练
            Double[,] x = new double[1, 160];
            Double[,] y = new double[1, 40];
            for (i = 0; i < 160; i++)
                x[0, i] = shuzu[i + (yuceshijian - 208), PlaceManager.Man.PlaceColumn];//从第二列读取20天数据，接着按列存入数组x

            for (i = 0; i < 40; i++)//从第二列读取最后五天数据，作为实测值，按列存入数组y
                y[0, i] = shuzu[i + (yuceshijian - 48), PlaceManager.Man.PlaceColumn];

            //对两个数组进行归一化
            Double max = 0.0;
            for (i = 0; i < 160; i++)
                if (x[0, i] > max)
                {
                    max = x[0, i];
                };
            for (i = 0; i < 8; i++)
                if (y[0, i] > max)
                {
                    max = y[0, i];
                };

            for (i = 0; i < 160; i++)
                x[0, i] = x[0, i] / max;
            for (i = 0; i < 40; i++)
                y[0, i] = y[0, i] / max;

            //定义一些需要用到的量
            double f = b;                      //精度控制参数
            double[,] Ch_v = new Double[IN_COUT, jds], Ch_w = new Double[jds, OUT_COUT]; //权矩阵修改量
            double[] ChgH = new Double[jds], ChgO = new Double[OUT_COUT];         //修改量矩阵
            double[] O1 = new Double[jds], O2 = new Double[OUT_COUT];             //隐层和输出层输出量

            int k, n;
            double temp;

            //对每个样本训练网络，对上述量赋初始值0
            Double e2 = f + 1;
            for (n = 0; e2 > f && n < xhcs; n++)
            {
                e2 = 0;
                for (j = 0; j < OUT_COUT; j++)
                    ChgO[j] = 0;
                for (j = 0; j < h; j++)
                    ChgH[j] = 0;
                for (j = 0; j < h; j++)
                    for (k = 0; k < OUT_COUT; k++)
                        Ch_w[j, k] = 0;
                for (j = 0; j < IN_COUT; j++)
                    for (k = 0; k < h; k++)
                        Ch_v[j, k] = 0;

                for (i = 0; i < COUT; i++)
                {
                    for (k = 0; k < h; k++)
                    {          //计算隐层输出向量
                        temp = 0;
                        for (j = 0; j < IN_COUT; j++)
                            temp = temp + x[i, j] * v[j, k];
                        O1[k] = 1 / (1 + Math.Exp(-temp));
                    }
                    for (k = 0; k < OUT_COUT; k++)
                    { //计算输出层输出向量
                        temp = 0;
                        for (j = 0; j < h; j++)
                            temp = temp + O1[j] * w[j, k];
                        O2[k] = 1 / (1 + Math.Exp(-temp));//网络训练修改规则的数学表达
                    }
                    for (j = 0; j < OUT_COUT; j++)   //计算输出误差
                        e2 = e2 + (y[i, j] - O2[j]) * (y[i, j] - O2[j]);
                    for (j = 0; j < OUT_COUT; j++)
                        ChgO[j] = O2[j] * (1 - O2[j]) * (y[i, j] - O2[j]);
                    for (j = 0; j < h; j++)
                        for (k = 0; k < OUT_COUT; k++)
                            Ch_w[j, k] += a * O1[j] * ChgO[k]; //累加所有样本训练后的改变量
                    for (j = 0; j < h; j++)
                    {
                        temp = 0;
                        for (k = 0; k < OUT_COUT; k++)
                            temp = temp + w[j, k] * ChgO[k];
                        ChgH[j] = temp * O1[j] * (1 - O1[j]);
                    }
                    for (j = 0; j < IN_COUT; j++)
                        for (k = 0; k < h; k++)
                            Ch_v[j, k] += a * x[i, j] * ChgH[k]; //累加所有样本训练后的改变量，消除样本顺序影响
                }

                for (j = 0; j < h; j++)           //修改输出层权矩阵
                    for (k = 0; k < OUT_COUT; k++)
                        w[j, k] = w[j, k] + Ch_w[j, k];
                for (j = 0; j < IN_COUT; j++)     //修改隐藏层权矩阵
                    for (k = 0; k < h; k++)
                        v[j, k] = v[j, k] + Ch_v[j, k];
                if (n % 1000 == 0)
                {
                    //logTileViewItem.Content += ("误差 : " + e2);
                    //logTileViewItem.Content += ("， 循环次数：" + n + "\n");
                }
            }
            //logTileViewItem.Content += ("最终误差 : " + e2);
            //logTileViewItem.Content += ("， 最终循环次数：" + n + "\n");

            //MessageBox.Show("网络训练完成！");

            //输出网络训练好时的隐藏层权矩阵
            for (i = 0; i < IN_COUT; i++)
            {
                strout[i] = (" ");
                for (j = 0; j < h; j++)
                {
                    //label5.Text += (v[i, j]);
                    strout[i] += (v[i, j] + " ");
                }

            }

            if (Directory.Exists(XmlConfigManager.Man.GetExerciseDataPath()) == false)//如果不存在就创建file文件夹
            {
                Directory.CreateDirectory(XmlConfigManager.Man.GetExerciseDataPath());
            }

            File.WriteAllLines(XmlConfigManager.Man.GetExerciseDataPath() + "\\" + PlaceManager.Man.PlaceName + "隐含层.txt", strout, Encoding.Default);
            //  MessageBox.Show("隐含层输出完毕！");

            //输出网络训练好时的输出层权矩阵
            for (i = 0; i < h; i++)
            {
                strout[i] = (" ");
                for (j = 0; j < OUT_COUT; j++)
                {
                    // label5.Text += (w[i, j]);
                    strout[i] += (w[i, j] + " ");
                }

            }
            File.WriteAllLines(XmlConfigManager.Man.GetExerciseDataPath() + "\\" + PlaceManager.Man.PlaceName + "输出层.txt", strout, Encoding.Default);
            //MessageBox.Show("输出层输出完毕！");

            //训练网络代码终止
        }

        //运用网络
        private void useNetwork()
        {
            //检查是否设置了预测站点
            if (null == PlaceManager.Man.PlaceName || PlaceManager.Man.PlaceName.Equals(""))
            {
                MessageBox.Show("请选择预测站点！");
                return;
            }

            //this.stepSize = 10;  //设置进度条每次增加的值
            //Timer_Restart();    //重新开始进度条

            //logTileViewItem.Content = "";
            DateTime zhidingshijian = PlaceManager.Man.PredictTime; //目前暂时指定为2011-09-01
            //从程序界面读取控制参数并存储
            Int32 jds = 10;//定义网络节点数
            Double xxl = 1.3;//定义网络学习率
            Double jdkz = 0.0001;//定义精度控制
            Int32 xhcs = 10000;//定义最大循环次数
            int yuceshijian = 0;
            Int32 OUT_COUT = 40;    //输出向量维数
            Int32 IN_COUT = 160;     //输入向量维数，站点数
            Int32 len;    //输出向量维数
            int i, j;
            int lenX = 0;
            Double[,] shuzu = new double[100000, 100];
            string[,] strArrX = new string[100000, 100];
            string[,] strArrY = new string[100000, 100];
            string[,] shijian = new string[100000, 2];
            string[] strArr = new string[20000];
            string[] strout = new string[10000];
            bool fe = File.Exists(PlaceManager.Man.FilePath);
            Double[,] x = new double[1, 160];
            Double[,] y = new double[1, 40];
            Double max = 0.0;
            double a = xxl;
            double b = jdkz;
            Int32 h = jds;
            double f = b;                      //精度控制参数
            double[,] Ch_v = new Double[IN_COUT, jds], Ch_w = new Double[jds, OUT_COUT]; //权矩阵修改量
            double[] ChgH = new Double[jds], ChgO = new Double[OUT_COUT];         //修改量矩阵
            double[] O1 = new Double[jds], O2 = new Double[OUT_COUT];             //隐层和输出层输出量
            //int k, n;
            double temp;
            //Int32 COUT = 1;    //样本数量，一日8个,此处暂时用例子中的6个


            Int32 LoopCout = xhcs;
            double[,] v = new Double[IN_COUT, jds];   //隐藏层权矩阵i,隐层节点最大数量为100
            double[,] w = new Double[jds, OUT_COUT];   //输出层权矩阵


            if (fe == false)
                MessageBox.Show("原始流量文件不存在！");
            else
                strArr = File.ReadAllLines(PlaceManager.Man.FilePath, Encoding.Default);//以文本方式逐行读取
            len = strArr.GetLength(0);
            // label5.Text += ("\n" + len);

            for (j = len - 1; j > 0; j--)
            {
                i = 0;
                for (int ctr = 0; ctr < strArr[j].Length - 1; ctr++)//对每行数据以字符为单位，逐个扫描
                {
                    if (strArr[j][ctr] == (' ') & strArr[j][ctr + 1] != (' '))//以一个或多个空格为分隔，按字符串方式存储到数组
                        i = i + 1;
                    else
                        strArrX[j, i] += strArr[j][ctr];
                }
                DateTime Time = DateTime.Parse(strArrX[j, 0] + " " + strArrX[j, 1]);
                if (Time < zhidingshijian)
                {
                    yuceshijian = j;

                    break;
                }
            }

            for (j = yuceshijian - 168; j < yuceshijian - 8; j++)
            {
                StationFlowData flowdata = new StationFlowData();

                i = 0;
                for (int ctr = 0; ctr < strArr[j].Length - 1; ctr++)//对每行数据以字符为单位，逐个扫描
                {
                    string[] temparr = strArr[j].Split(new char[] { ' ' });
                    for (int ix = 0, n = 0; ix < temparr.Length; ix++)
                    {
                        if (temparr[ix] != "")
                        {
                            strArrX[j, n] = temparr[ix];
                            n += 1;
                            i = n + 1;
                        }
                    }

                }
                lenX = i;//统计每行含有的数据个数
                //label5.Text += ("\n数组含" + (lenX + 1) + "个数");
                for (i = 0; i < 2; i++)//将日期和时间存到shijian数组中
                {
                    shijian[j, i] = (strArrX[j, i]);
                }

                for (i = 2; i <= lenX; i++)//排除日期和时间，从第三列开始全部转换为双精度格式
                {
                    shuzu[j, i] = Convert.ToDouble(strArrX[j, i]);
                }
            }

            Double[] Input = new double[160];
            Double[] shice = new double[40];
            //for (i = 0; i < 160; i++)
            //    x[0, i] = shuzu[i + (len - 88), 2];
            for (i = 0; i < 160; i++)
                Input[i] = shuzu[i + (yuceshijian - 168), 3];
            //for (i = 0; i < 40; i++)
            //    shice[i] = shuzu[i + (yuceshijian - 168), 3];

            max = 0.0;
            for (i = 0; i < 160; i++)
                if (Input[i] > max)
                {
                    max = Input[i];
                };

            for (i = 0; i < 160; i++)
                Input[i] = Input[i] / max;

            // MessageBox.Show("流量数据读取完毕！");

            //检查训练后的参数文件是否存在
            if (!File.Exists(XmlConfigManager.Man.GetExerciseDataPath() + "\\" + PlaceManager.Man.PlaceName + "输出层.txt"))
            {
                MessageBox.Show("请先训练网络！");
                return;
            }

            strArr = File.ReadAllLines(XmlConfigManager.Man.GetExerciseDataPath() + "\\" + PlaceManager.Man.PlaceName + "输出层.txt", Encoding.Default);//读取已训练好的网络输出层权矩阵

            for (j = 0; j < 10; j++)
            {
                i = 0;
                for (int ctr = 0; ctr < strArr[j].Length; ctr++)
                {
                    if (strArr[j][ctr] == (' '))
                        i = i + 1;
                    else
                        strArrX[j, i] += strArr[j][ctr];
                }
                lenX = i;
                //label5.Text += ("\nv数组含" + (lenX + 1) + "个数");
                for (i = 0; i < lenX - 1; i++)
                {
                    //label5.Text += ("\n" + i + "-" + strArrX[j, i+1]);
                    w[j, i] = Convert.ToDouble(strArrX[j, i + 1]);
                }
            }

            //检查训练后的参数文件是否存在
            if (!File.Exists(XmlConfigManager.Man.GetExerciseDataPath() + "\\" + PlaceManager.Man.PlaceName + "隐含层.txt"))
            {
                MessageBox.Show("请先训练网络！");
                return;
            }

            strArr = File.ReadAllLines(XmlConfigManager.Man.GetExerciseDataPath() + "\\" + PlaceManager.Man.PlaceName + "隐含层.txt", Encoding.Default);//读取已训练好的网络隐藏层权矩阵

            for (j = 0; j < 160; j++)
            {
                i = 0;
                for (int ctr = 0; ctr < strArr[j].Length; ctr++)
                {
                    if (strArr[j][ctr] == (' '))
                        i = i + 1;
                    else
                        strArrY[j, i] += strArr[j][ctr];
                }
                lenX = i;
                // label5.Text += ("\nv数组含" + (lenX + 1) + "个数");
                for (i = 0; i < lenX - 1; i++)
                {
                    // label5.Text += ("\n" + i + "-" + strArrY[j, i+1]);
                    v[j, i] = Convert.ToDouble(strArrY[j, i + 1]);
                }
            }

            //MessageBox.Show("网络数据读取完毕！");


            //根据已训练好的网络，代入需要的输入数据计算得到输出数据，再反归一化即得到预测值
            for (i = 0; i < h; i++)
            {
                temp = 0;
                for (j = 0; j < IN_COUT; j++)
                    temp += Input[j] * v[j, i];
                O1[i] = 1 / (1 + Math.Exp(-temp));
            }
            for (i = 0; i < OUT_COUT; i++)
            {
                temp = 0;
                for (j = 0; j < h; j++)
                    temp += O1[j] * w[j, i];
                O2[i] = 1 / (1 + Math.Exp(-temp));
            }

            //logTileViewItem.Content += ("实测序列最大流量" + max + "\n");
            // 有修改

            List<StationFlowData> flowdataList = new List<StationFlowData>();
            strout[0] += ("日期" + "\t" + "时间" + "\t" + "预测值" + "\t");
            DateTime temptime = PlaceManager.Man.PredictTime.AddHours(2);
            for (i = 1; i <= OUT_COUT; i++)
            {
                double flow = O2[i - 1] * max;
                StationFlowData flowdata = new StationFlowData();
                flowdata.Time = temptime + TimeSpan.FromHours(3 * (i - 1));
                flowdata.Flow = flow;
                flowdataList.Add(flowdata);

                strout[i] = (" ");
                strout[i] += ("\n" + flowdata.Time + "\t" + flow + "\t");//以i=1起头是为了给文件第一行标题让位


            };

            //将每一个站点的预测结果数据放进总的预测结果字典中，以便导出所有数据和显示图像
            if (!forcastResultData.ContainsKey(PlaceManager.Man.PlaceName))
            {
                forcastResultData.Add(PlaceManager.Man.PlaceName, flowdataList);
            }
            else
            {
                forcastResultData[PlaceManager.Man.PlaceName] = flowdataList;
            }

            rdMan.SetStationFlowDataList(PlaceManager.Man.PlaceName, flowdataList);
            this.rgv.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle, new Action(SetGridView));
            //SetGridView();
            //borChart.Child = rdMan.BuildPredictChart(PlaceManager.Man.PlaceName, flowdataList);

            //String test = XmlConfigManager.Man.GetSaveDataPath() + "\\" + PlaceManager.Man.PlaceName + "输出.csv";

            File.WriteAllLines(XmlConfigManager.Man.GetSaveDataPath() + "\\" + PlaceManager.Man.PlaceName + "输出.csv", strout, Encoding.Default);
            //MessageBox.Show("预测完毕！");
        }

        void SetGridView()
        {
            rgv.ItemsSource = null;
            rgv.ItemsSource = rdMan.reportList;
        }

        //左边侧菜单选择之后执行的操作
        private void RadPanelBarItem_Selected(object sender, Telerik.Windows.RadRoutedEventArgs e)
        {
            String placeName = (sender as Telerik.Windows.Controls.RadPanelBarItem).Name.ToString();
            PlaceManager.Man.SetSelectedMenu(placeName);

            //检查字典中是否有选中的站点的数据
            if (!forcastResultData.ContainsKey(PlaceManager.Man.PlaceName))
            {
                MessageBox.Show("请先进行预测！");
                return;
            }
            List<StationFlowData> flowdataList = forcastResultData[PlaceManager.Man.PlaceName];
            if (null == flowdataList || flowdataList.Count == 0)
            {
                MessageBox.Show("请先进行预测！");
                return;
            }

            //控制预测结果显示小窗口的最大最小化
            resultTileViewItem.TileState = Telerik.Windows.Controls.TileViewItemState.Minimized;
            lineTileViewItem.TileState = Telerik.Windows.Controls.TileViewItemState.Maximized;

            //添加预测结果数据至数据表格
            rdMan.SetStationFlowDataList(PlaceManager.Man.PlaceName, flowdataList);
            SetGridView();
            //添加预测结果数据至曲线
            //borChart.Child = rdMan.BuildPredictChart(PlaceManager.Man.PlaceName, flowdataList);
            int dataCount = flowdataList.Count;
            List<CompareFlowData> compareFlowDataList = new List<CompareFlowData>();
            foreach (StationFlowData sfd in flowdataList)
            {
                CompareFlowData compareFlowData = new CompareFlowData();
                compareFlowData.Time = sfd.Time;
                compareFlowData.ForcastedFlow = sfd.Flow;
                compareFlowData.RealFlow = 0.00;

                compareFlowDataList.Add(compareFlowData);
            }
            /*
            //在日志小窗口显示日志
            logTileViewItem.Content = "当前选择的预测站点是：" + placeName + "\n";
            logTileViewItem.Content += "正在加载数据文件：" + PlaceManager.Man.FilePath + " ...\n";
            logTileViewItem.Content += "正在加载数据文件第 " + PlaceManager.Man.PlaceColumn.ToString() + " 列（" + placeName + ") 的数据 ...\n";
            */
            //*********************************************************************************************//
            int yuceshijian = 0;
            DateTime zhidingshijian = PlaceManager.Man.PredictTime; //目前暂时指定为2011-09-01
            int i, j;
            Int32 len;    //流量数据行数
            int lenX = 0;//每行数据个数

            Double[,] shuzu = new double[100000, 100];
            string[,] strArrX = new string[100000, 100];
            string[] strArr = new string[100000];
            string[] strout = new string[100000];
            bool fe = File.Exists(PlaceManager.Man.FilePath);

            if (fe == false)
            {
                MessageBox.Show("原始流量文件不存在！");
            }
            else
            {
                strArr = File.ReadAllLines(PlaceManager.Man.FilePath, Encoding.Default);//以文本方式逐行读取
            }

            len = strArr.GetLength(0);//计算文件行数
            for (j = len - 1; j > 0; j--)
            {
                i = 0;
                for (int ctr = 0; ctr < strArr[j].Length - 1; ctr++)//对每行数据以字符为单位，逐个扫描
                {
                    if (strArr[j][ctr] == (' ') & strArr[j][ctr + 1] != (' '))//以一个或多个空格为分隔，按字符串方式存储到数组
                        i = i + 1;
                    else
                        strArrX[j, i] += strArr[j][ctr];
                }
                DateTime Time = DateTime.Parse(strArrX[j, 0] + " " + strArrX[j, 1]);
                if (Time <= zhidingshijian)
                {
                    yuceshijian = j + 1;

                    break;
                }
                yuceshijian = j + 1;
            }

            //读取未来5天的数据
            for (j = yuceshijian; j < len && (j < (yuceshijian + dataCount)); j++)
            {
                i = 0;
                for (int ctr = 0; ctr < strArr[j].Length - 1; ctr++)
                {
                    if (strArr[j][ctr] == (' ') & strArr[j][ctr + 1] != (' ')) i = i + 1;
                }
                lenX = i;
                for (i = 2; i <= lenX; i++)//排除日期和时间，从第三列开始全部转换为双精度格式
                {
                    shuzu[j, i] = Convert.ToDouble(strArrX[j, i]);
                }
            }

            for (i = 0; i < dataCount && i + yuceshijian < len; i++)//从读取和预测时间相同的五天真实数据
            {
                compareFlowDataList[i].RealFlow = shuzu[i + yuceshijian, PlaceManager.Man.PlaceColumn];
            }
            //添加预测结果数据至曲线
            borChart.Child = rdMan.BuildPredictChart(PlaceManager.Man.PlaceName, compareFlowDataList);
        }

        //开始预测按钮触发事件
        private void forcastButton_Click(object sender, RoutedEventArgs e)
        {
            forcastThread = new Thread(new ThreadStart(forcast));   //设置预报线程
            forcastThread.Start();  //启动预报线程
            Timer_Restart();
        }

        //预报函数
        private void forcast()
        {
            currentStationSequence = 1; //先置为1
            foreach (String placeName in stationNames)
            {
                PlaceManager.Man.SetSelectedMenu(placeName);
                updateCuurentCalculateLable("");    //更新界面显示的当前操作，下面都是相同的
                String currentStationString = "开始预测站点：" + placeName;
                updateCuurentCalculateLable(currentStationString);

                this.timer.Start(); //启动timer，开始进度条

                updateCuurentCalculateLable(currentStationString + "，正在加载数据文件：" + PlaceManager.Man.FilePath + " ...");
                updateCuurentCalculateLable(currentStationString + "，正在加载数据文件第 " + PlaceManager.Man.PlaceColumn.ToString() + " 列（" + placeName + ") 的数据 ...\n");
                updateCuurentCalculateLable(currentStationString + "，正在进行网络训练...");

                trainNetwork(); //训练网络
                updateCuurentCalculateLable(currentStationString + "，网络训练完毕");
                updateCuurentCalculateLable(currentStationString + "，正在进行网络运用...");

                useNetwork();   //运用网络

                updateCuurentCalculateLable(currentStationString + "，网络运用完毕");

                currentStationSequence++;
            }
            //this.timer.Stop();
            updateCuurentCalculateLable("预报完毕");
            //激活保存按钮
            this.saveButton.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle, new Action(enableSaveButton));
        }

        //更新界面显示的当前操作的异步调用函数
        private void updateCuurentCalculateLable(String content)
        {
            this.cuurentCalculateLable.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle,
                new Action<String>(updateCuurentCalculateLableContent), content);
        }
        //更新界面显示的当前操作
        private void updateCuurentCalculateLableContent(String content)
        {
            cuurentCalculateLable.Content = content;
        }
        //将保存按钮设为可用
        private void enableSaveButton()
        {
            saveButton.IsEnabled = true;
        }
        
        //保存数据按钮触发事件
        private void saveButton_Click(object sender, RoutedEventArgs e)
        {
            //检查字典中是否有选中的站点的数据
            if (forcastResultData.Count == 0)
            {
                MessageBox.Show("请先进行预测！");
                return;
            }

            //选择文件保存路径
            System.Windows.Forms.SaveFileDialog saveFileDialog = new System.Windows.Forms.SaveFileDialog();
            saveFileDialog.Title = "请选择预报结果文件保存路径";
            saveFileDialog.Filter = "csv files (*.csv) | *.csv";
            saveFileDialog.ShowDialog();
            String filePath = saveFileDialog.FileName;

            if (null == filePath || filePath.Equals("")) return;    //如果没有指定文件保存路径，则不保存预测结果

            //处理文件头，日期和时间
            List<string> rowStringList = new List<string>();
            //标题
            String rowString = "日期" + "\t" + "时间" + "\t";
            rowStringList.Add(rowString);

            String test = rowStringList[0];

            //needAddDateTime用于判断是否需要写入日期和时间，第一个站点的数据需要写入，后面的数据不用写
            Boolean needAddDateTime = true;

            foreach (KeyValuePair<String, List<StationFlowData>> forcastResultKVP in forcastResultData)
            {
                String stationName = forcastResultKVP.Key;
                List<StationFlowData> stationFlowData = forcastResultKVP.Value;

                int index = 0;  //遍历rowStringList的索引
                rowStringList[index] += stationName + "\t";   //添加站点名称

                int i = 0;  //遍历stationFlowData的索引
                for (i = 0; i < stationFlowData.Count; i++)
                {
                    index++;
                    String rowStringTemp = "\n";
                    if (needAddDateTime)    //第一个站点的数据需要写入日期和时间，后面的数据不用写
                    {
                        rowStringTemp += stationFlowData[i].Time + "\t";    //加入日期和时间
                        rowStringList.Add(rowStringTemp);
                    }

                    rowStringList[index] += stationFlowData[i].Flow + "\t";    //加入数据
                }

                needAddDateTime = false;    //第一个站点后面的站点不用写入日期和时间
            }
            File.WriteAllLines(filePath, rowStringList, Encoding.Default);
            MessageBox.Show("预报结果保存成功！");
        }
    }
}
